보안 필터링
보안 필터링 (Security Filtering)
개요
보안 필터링이란 외부로부터 유입되는 입력 데이터가 시스템의 의도된 동작을 방해하거나 보안 취약점을 악용하지 않도록, 사전에 정의된 규칙에 따라 데이터를 검증, 변환 또는 차단하는 보안 메커니즘을 의미한다. 보안 필터링은 입력값 검증(Input Validation), 정규화(Normalization), 출력값 인코딩(Output Encoding)을 모두 포괄하는 종합적인 데이터 제어 프로세스이다.
현대적인 애플리케이션은 사용자 입력, API 요청, 파일 업로드 등 다양한 경로를 통해 외부 데이터를 수신한다. 이때 입력값에 대한 적절한 필터링이 이루어지지 않으면, 공격자가 악의적인 구문을 삽입하여 데이터베이스를 조작하거나(Injection), 사용자 브라우저에서 임의의 스크립트를 실행(XSS)시키는 등의 심각한 보안 사고로 이어질 수 있다. 특히, 단순한 문자열 치환 방식의 필터링은 대소문자 혼용이나 다중 인코딩과 같은 우회 기법에 의해 무력화될 가능성이 높다. 따라서 보안 필터링은 '신뢰할 수 없는 모든 입력값은 잠재적으로 위험하다'는 전제하에 시스템의 무결성과 가용성을 보호하는 필수적인 방어 계층이다.
필터링의 기본 원리
입력값 검증 vs 출력값 인코딩 vs 이스케이프
보안 필터링은 데이터의 흐름에 따라 크게 세 가지 단계로 나뉜다.
- 입력값 검증 (Input Validation): 데이터가 시스템 내부로 진입하는 시점에 형식이 올바른지, 허용된 범위 내의 값인지 확인하는 과정이다. (예: 나이 입력란에 숫자가 아닌 문자가 들어왔는지 확인)
- 출력값 인코딩 (Output Encoding): 검증된 데이터를 사용자 화면이나 외부 시스템으로 출력할 때, 데이터가 실행 코드로 해석되지 않도록 특수 문자를 안전한 형태로 변환하는 과정이다. (예:
<를<로 변환) - 이스케이프 (Escaping): 특수 문자가 가진 제어 문자로서의 의미를 제거하기 위해 앞에 특정 문자(예:
\)를 붙여 일반 문자로 처리하게 하는 기법이다. 주로 SQL 쿼리나 쉘 명령어 작성 시 사용된다.
화이트리스트 vs 블랙리스트
필터링 규칙을 설정하는 방식은 크게 두 가지 전략으로 구분된다.
| 구분 | 화이트리스트 (Whitelist) | 블랙리스트 (Blacklist) |
|---|---|---|
| 정의 | 허용된 안전한 값만 통과시키고 나머지는 모두 차단 | 알려진 위험한 값만 차단하고 나머지는 모두 허용 |
| 접근 방식 | 긍정적 검증 (Positive Validation) | 부정적 검증 (Negative Validation) |
| 보안성 | 매우 높음 (미지의 공격까지 방어 가능) | 낮음 (새로운 공격 패턴에 취약함) |
| 유지보수 | 초기 설정 비용이 높고 엄격함 | 설정이 간편하나 지속적인 업데이트 필요 |
| 적용 사례 | 정규표현식을 이용한 형식 검증, Enum 타입 체크 | 특정 금지어(Keyword) 필터링, IP 차단 목록 |
주요 공격 유형별 필터링 전략
SQL Injection
공격자가 SQL 쿼리문에 악의적인 구문을 삽입하여 데이터베이스를 조작하는 공격이다.
* 전략: 입력값에서 ', --, ; 등의 특수문자를 필터링하거나, Prepared Statement(매개변수화 쿼리)를 사용하여 입력값을 단순 텍스트로 처리한다.
XSS (Cross-Site Scripting)
웹 페이지에 악성 스크립트를 삽입하여 사용자의 세션을 탈취하거나 페이지를 변조하는 공격이다.
* 전략: <script>, <iframe>, onerror 등 HTML 태그 및 이벤트 핸들러를 제거하거나, HTML Entity로 인코딩한다.
[HTML 인코딩 예시]
* 입력값: <script>alert('XSS')</script>
* 인코딩 후: <script>alert('XSS')</script> (브라우저에서 실행되지 않고 텍스트로 출력됨)
OS Command Injection
애플리케이션이 시스템 명령어를 실행하는 함수를 사용할 때, 입력값을 통해 임의의 OS 명령어를 실행하는 공격이다.
* 전략: &, |, ;, $ 등 쉘 메타문자를 엄격히 필터링하고, 가급적 시스템 명령어를 직접 호출하는 API 사용을 지양한다.
[코드 예제] 필터링 적용 전후 비교 (Java/Spring 기준)
위험한 코드 (Vulnerable)
// 사용자 입력값을 그대로 쿼리에 결합 (SQL Injection 위험)
String query = "SELECT * FROM users WHERE username = '" + request.getParameter("username") + "'";
ResultSet rs = statement.executeQuery(query);
안전한 코드 (Secure)
// Prepared Statement를 사용하여 입력값을 파라미터로 처리
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, request.getParameter("username")); // 자동으로 이스케이프 처리됨
ResultSet rs = pstmt.executeQuery();
필터링 구현 단계 및 위치
클라이언트 사이드 vs 서버 사이드
- 클라이언트 사이드 (Frontend): JavaScript 등을 이용한 검증은 사용자 경험(UX)을 향상시키지만, 프록시 툴(Burp Suite 등)을 통해 쉽게 우회 가능하다. 따라서 보조적인 수단으로만 사용해야 한다.
- 서버 사이드 (Backend): 모든 입력값은 반드시 서버에서 최종 검증되어야 한다. 이는 보안의 최후 보루이자 필수 단계이다.
애플리케이션 계층별 적용 위치
- Filter/Interceptor: 공통적인 보안 필터링(XSS 필터, 인증 체크)을 전역적으로 적용하는 단계.
- DTO (Data Transfer Object):
@Valid또는@NotNull등의 어노테이션을 통해 데이터 타입, 길이, 필수 값 여부를 검증하는 단계. - Service/Domain Layer: 비즈니스 로직에 따른 세부적인 값의 범위 및 유효성을 검증하는 단계.
필터링 우회 기법과 대응 방안
주요 우회 기법
- 대소문자 혼용:
<sCrIpT>와 같이 대소문자를 섞어 블랙리스트 필터를 우회. - 인코딩 우회: URL 인코딩(
%3C), Hex 인코딩, Unicode 인코딩을 사용하여 필터링 규칙을 회피. - Null Byte 삽입:
%00(Null Byte)를 삽입하여 문자열 끝으로 인식하게 만들어 이후의 검증 로직을 무력화.
정규화(Normalization) 과정
우회를 방지하기 위해서는 데이터를 검증하기 전, 데이터를 표준 형태로 변환하는 정규화 과정이 선행되어야 한다.
graph LR;
A[외부 입력값] --> B[디코딩 URL/HTML/Base64]
B --> C[특수문자/공백 제거 및 표준화]
C --> D[대소문자 통일 Lower/Upper Case]
D --> E[최종 필터링/검증]
E --> F[시스템 유입]
보안 필터링 모범 사례 (Best Practices)
설계 원칙
- 최소 권한 원칙: 입력값에 대해 꼭 필요한 권한과 형식만 허용한다.
- 심층 방어 (Defense in Depth): 한 곳의 필터링이 뚫리더라도 다음 단계에서 방어할 수 있도록 다중 계층 필터링을 적용한다.
- Fail-Safe Defaults: 검증 결과가 불분명할 경우 '허용'이 아닌 '차단'을 기본값으로 설정한다.
추천 필터링 라이브러리
직접 정규표현식을 작성하는 것보다 검증된 보안 라이브러리를 사용하는 것이 안전하다.
| 라이브러리 | 주요 용도 | 특징 |
|---|---|---|
| OWASP ESAPI | 종합 보안 라이브러리 | 인코딩, 검증, 암호화 등 광범위한 보안 기능 제공 |
| Naver Lucy-XSS | XSS 방어 | 한국어 환경에 최적화된 HTML 화이트리스트 기반 필터 |
| Apache Commons Validator | 입력값 검증 | 이메일, URL, 날짜 등 표준 형식 검증에 유용 |
| Hibernate Validator | Bean Validation | Java 표준(JSR 380) 기반의 DTO 레벨 검증 |
실제 필터링 설정 예시 (Spring Security / Filter)
아래는 모든 요청 파라미터를 순회하며 화이트리스트 기반의 정규표현식으로 검증하는 안전한 필터 구현 예시이다.
public class SecurityFilter implements Filter {
// 화이트리스트: 영문자, 숫자만 허용하는 정규표현식
private static final Pattern SAFE_PATTERN = Pattern.compile("^[a-zA-Z0-9]*$");
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
Map<String, String[]> parameterMap = req.getParameterMap();
for (String paramName : parameterMap.keySet()) {
String[] values = parameterMap.get(paramName);
for (String value : values) {
if (value != null && !SAFE_PATTERN.matcher(value).matches()) {
// 허용되지 않은 형식이 발견되면 즉시 차단
throw new SecurityException("Invalid input detected in parameter: " + paramName);
}
}
}
chain.doFilter(request, response);
}
}
관련 가이드라인
더 자세한 보안 표준 및 가이드라인은 아래의 공신력 있는 기관의 문서를 참조하십시오. * OWASP Top 10 - 웹 애플리케이션 보안 위험 Top 10 * OWASP Input Validation Cheat Sheet - 입력값 검증 상세 가이드 * KISA 소프트웨어 보안 약점 진단 가이드 - 한국인터넷진흥원 보안 가이드라인
이 문서는 AI 모델(gemma-4-31b)에 의해 생성된 콘텐츠입니다.
주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.